from __future__ import annotations

from typing import TYPE_CHECKING

from sqlalchemy import Date, Enum, Float, ForeignKey, JSON, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.db.base_class import BaseEntity

if TYPE_CHECKING:
  from .relationship import Relationship
  from .user import User


class CycleLog(BaseEntity):
  __tablename__ = "cycle_logs"

  user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
  relationship_id: Mapped[int | None] = mapped_column(ForeignKey("relationships.id"), index=True)
  start_date: Mapped[Date] = mapped_column(Date)
  end_date: Mapped[Date | None] = mapped_column(Date, nullable=True)
  symptoms_json: Mapped[dict | None] = mapped_column(JSON, default=dict)
  notes: Mapped[str | None] = mapped_column(Text)

  user: Mapped["User"] = relationship(back_populates="cycle_logs", lazy="joined")
  predictions: Mapped[list["CyclePrediction"]] = relationship(back_populates="log", lazy="selectin")
  relationship: Mapped["Relationship | None"] = relationship("Relationship", lazy="joined")


class CyclePrediction(BaseEntity):
  __tablename__ = "cycle_predictions"

  user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
  log_id: Mapped[int | None] = mapped_column(ForeignKey("cycle_logs.id"), nullable=True)
  relationship_id: Mapped[int | None] = mapped_column(ForeignKey("relationships.id"), index=True)
  phase: Mapped[str] = mapped_column(
    Enum("menstruation", "luteal", "follicular", "fertile", "safe", name="cycle_phase")
  )
  start_date: Mapped[Date] = mapped_column(Date)
  end_date: Mapped[Date] = mapped_column(Date)
  confidence: Mapped[float] = mapped_column(Float, default=0.7)

  log: Mapped[CycleLog | None] = relationship(back_populates="predictions", lazy="joined")
  user: Mapped["User"] = relationship(lazy="joined")
  relationship: Mapped["Relationship | None"] = relationship("Relationship", lazy="joined")
